using System;
using System.Collections.Generic;
using System.Text;
using System.Threading;
using AopLoadBalancer.Server.DataAccess;

namespace AopLoadBalancer.Server.BusinessLogic
{
    /// <summary>
    /// Responsible for notifying central point that service is alive (in sql database)
    /// </summary>
    public class AliveNotifier
    {

        private volatile bool enabled = false;
        private ManualResetEvent enabledEvent;

        private volatile bool stopped = false;

        private AliveNotification currentNotification;

        private Thread notifier;

        //every none minute
        internal static readonly TimeSpan notificationInterval = new TimeSpan(0, 0, 0, 30);

        public bool Enabled
        {
            get { return enabled; }
            set
            {
                enabled = value;
                if (enabled)
                {
                    enabledEvent.Set();
                }
                else
                {
                    enabledEvent.Reset();
                }
            }
        }


        public AliveNotifier(string serviceUrl, string serviceId)
        {
            EnsureRowExists(serviceId, serviceUrl);

            enabledEvent = new ManualResetEvent(enabled);

            notifier = new Thread(NotifyLoop);
            notifier.IsBackground = true;

            notifier.Start();
        }

        public void Stop()
        {
            stopped = true;
        }

        /// <summary>
        /// Ensures the row exists in database table.
        /// </summary>
        private void EnsureRowExists(string serviceId, string serviceUrl)
        {
            using (DalSession session = new DalSession(ServerConfig.ConnectionString))
            {
                session.BeginTransaction();
                AliveNotificationDal dal = new AliveNotificationDal(session);
                AliveNotification aliveNotification = dal.GetByUrl(serviceUrl);
                if (aliveNotification == null)
                {
                    aliveNotification = new AliveNotification(serviceId, serviceUrl, DateTime.Now);
                    dal.Add(aliveNotification);
                }
                else
                {
                    aliveNotification.LastAliveTick = DateTime.Now;
                    dal.Update(aliveNotification);
                }

                currentNotification = aliveNotification;

                session.CommitTransaction();
            }
        }

        private void NotifyLoop()
        {
            while (!stopped)
            {
                //wait for enabled state
                enabledEvent.WaitOne();
                if (enabled)
                {
                    Notify();
                    Thread.Sleep(notificationInterval);
                }
            }
        }


        /// <summary>
        /// Notifies this instance.
        /// </summary>
        private void Notify()
        {
            using (DalSession session = new DalSession(ServerConfig.ConnectionString))
            {
                AliveNotificationDal dal = new AliveNotificationDal(session);
                currentNotification.LastAliveTick = DateTime.Now;
                dal.Update(currentNotification);
            }
        }
    }
}